/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - geometry
// Copyright( c) 2015.  All Rights Reserved
//
// File:		AEVertexDescriptor.h
// Author:		Gianluca Belardelli
// Date:		09/02/2015
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AEVERTEXDESCRIPTOR_H_
#define _AEVERTEXDESCRIPTOR_H_

/// \brief 
///   Structure that defines the vertex format for mesh buffer vertices (VisMeshBuffer_cl class)
/// 
/// This structure allows you to define your own vertex format for rendering mesh buffers.
/// 
/// The m_sStride member has to be set to the size of the vertex structure.
/// 
/// Each member defines the offset (in bytes) within the structure; -1 indicates that the respective stream
/// is not defined (default). To calculate the offset, use e.g. offsetof(structurename,member).
/// Furthermore, the offset values for each attribute have to contain a format specifier, which has to be added to
/// the offset field (e.g. iOfs = offsetof(struct, structmember) | VERTEXDESC_FORMAT_FLOAT3).
///
/// Note that secondary color information is currently not supported.
/// 
/// Sono supportati i seguenti specificatori di formato:
/// \li \b AEVERTEXDESC_FORMAT_FLOAT : Singolo comonente float.
/// \li \b AEVERTEXDESC_FORMAT_FLOAT2 : 2 componenti float.
/// \li \b AEVERTEXDESC_FORMAT_FLOAT3 : 3 componenti float.
/// \li \b AEVERTEXDESC_FORMAT_FLOAT4 : 4 componenti float.
/// \li \b AEVERTEXDESC_FORMAT_UBYTE4N : 4 componenti unsigned byte.
/// \li \b AEVERTEXDESC_FORMAT_SHORT2N : 2 componenti signed short.
/// \li \b AEVERTEXDESC_FORMAT_SHORT4N : 4 componenti signed short.
/// \li \b AEVERTEXDESC_FORMAT_HALF2 : 2 componenti half (half=16bit floating point).
/// \li \b AEVERTEXDESC_FORMAT_HALF4 : 4 componenti half (half=16bit floating point).
/// \li \b AEVERTEXDESC_FORMAT_USHORT2N : 2 componenti unsigned short.
/// \li \b AEVERTEXDESC_FORMAT_USHORT4N : 4 componenti unsigned short.
/// \li \b AEVERTEXDESC_FORMAT_BYTE4 : 4 componenti unsigned byte.
/// \li \b AEVERTEXDESC_FORMAT_SHORT2 : 2 componenti signed short.
/// \li \b AEVERTEXDESC_FORMAT_SHORT4 : 4 componenti signed short.
///
/// \sa AEMeshBuffer
/// \sa AEMeshBuffer::AllocateVertices
/// \sa AEMeshBufferObject
struct AEVertexDescriptor
{
public:
	/** @name Membri pubblici */
	/// @{
	AEINT16 m_sStride;            ///< stride of the vertex structure; must be set to the size of the vertex structure
	AEINT16 m_sPosOfs;            ///< offset of the position vector in the structure. Use bitwise OR with format bitflag constants of type VERTEXDESC_FORMAT_xyz to force a specific format
	AEINT16 m_sColorOfs;          ///< offset of the color vector in the structure. Use bitwise OR with format bitflag constants of type VERTEXDESC_FORMAT_xyz to force a specific format
	AEINT16 m_sNormalOfs;         ///< offset of the normal vector in the structure. Use bitwise OR with format bitflag constants of type VERTEXDESC_FORMAT_xyz to force a specific format
	AEINT16 m_sTexCoordOfs[AEMAX_MESHBUFFER_TEXCOORDS];   ///< offset of the sets of texture coordinates in the structure. Use bitwise OR with format bitflag constants of type VERTEXDESC_FORMAT_xyz to force a specific format
	AEINT16 m_sSecondaryColorOfs; ///< offset of the secondary color. Not supported on all platforms
	
	// do not put members in between here
	
	AEUINT8 m_byFirstTexCoord;     ///< Index of the first used texture coordinate set. Set automatically by ComputeHash() or at serialization time.
	AEUINT8 m_byLastTexCoord;      ///< Index of the last used texture coordinate set. Set automatically by ComputeHash() or at serialization time.
	AEUINT32 m_uiHash;               ///< Hash value. Set automatically when computing the hash or at serialization time.
	
	/// @}
public:
	/** @name Costruttore e inizializzazione */
	/// \brief Costruttore che resetta tutti i membri.
	AE_FORCEINLINE AEVertexDescriptor( void );

	/// \brief
	/// Imposta tutti i membri con un valore indefinito.
	AE_FORCEINLINE void Reset( void ); 

	/// \brief Internal function that fills up flags for all members
	AE_DLLIMPEXP void SetFormatDefaults( void );

	/** @name Propriet&agrave; */
	/// @{
	/// \brief
	///   Determines whether this descriptor is valid. Does NOT perform a platform-specific validation; rather, it only performs a simple validation
	///   of the structure members.
	AE_DLLIMPEXP AEBOOL32 IsValidDescriptor( void ) const;

	/// \brief Indica se questo descrittore ha informazioni riguardo la posizione.
	AE_FORCEINLINE AEBOOL32 HasPosition( void ) const;

	/// \brief Indica se questo descrittore ha informazioni riguardo il colore.
	AE_FORCEINLINE AEBOOL32 HasColor( void ) const;

	/// \brief Indica se questo descrittore ha informazioni riguardo il colore secondario.
	AE_FORCEINLINE AEBOOL32 HasSecondaryColor( void ) const;

	/// \brief Indica se questo descrittore ha informazioni riguardo il vettore delle normali.
	AE_FORCEINLINE AEBOOL32 HasNormal( void ) const;

	/// \brief Indicates whether this descriptor has texture coordinate information 
	/// for a specific texture channel.
	/// The number of supported texture coordinate channels is defined by the global
	/// AEMAX_MESHBUFFER_TEXCOORDS constant (currently 16).
	/// \param iChannel
	///   texture channel to query. Must be [0..AEMAX_MESHBUFFER_TEXCOORDS-1]
	AE_FORCEINLINE AEBOOL32 HasTexCoord( AEINT32 nChannel = 0 ) const;

	/// \brief
	///   Returns the stream bitmask (each bit of type VERTEX_STREAM_xyz) for this descriptor. Naturally,
	///   the VERTEX_STREAM_INDEXBUFFER bit is never set
	AE_DLLIMPEXP AEUINT32 GetStreamMask( void ) const;

	/// @}
	/** @name Static Helpers */
	/// @{
	/// \brief
	///   Copies n vertices from source buffer to destination buffer using distinct vertex descriptors for both buffers
	/// All members that are defined in the destination descriptor but not in the source are initialized to zero. The same goes for members that have
	/// more components in the target buffer (e.g. source float2(1.0,2.0) will be copied as float3(1.0,2.0,0.0) if the target uses float3 as component format).
	/// This function also takes care of all different combinations of formats, e.g. VFloat16, AEFLOAT32, AEINT16 or byte.
	/// \param pDstBuffer Destination system memory buffer
	/// \param dstDesc vertex format of destination vertices
	/// \param pSrcBuffer Source system memory buffer
	/// \param srcDesc vertex format of source vertices
	/// \param iVertexCount number of vertices to copy
	AE_DLLIMPEXP static void CopyVertices( void *lpDstBuffer, const AEVertexDescriptor &dstDesc, const void *lpSrcBuffer, const AEVertexDescriptor &srcDesc, AEINT32 nVertexCount );

	/// \brief Returns a format constant of type VERTEXDESC_FORMAT_FLOAT3,
	/// for the specified descriptor member (e.g. m_sPosOfs)
	static AE_FORCEINLINE AEUINT32 GetComponentFormat( AEINT32 nValue );

	/// \brief Returns a format string for each constant of type 
	/// VERTEXDESC_FORMAT_FLOAT3. Can be used for debug purposes
	static AE_FORCEINLINE const char *GetComponentFormatString( AEINT32 nFormat );

	/// \brief Returns the offset (in bytes) for the specified 
	///descriptor member (e.g. m_sPosOfs)
	static AE_FORCEINLINE AEINT32 GetComponentOffset( AEINT32 nValue );

	/// \brief Returns the number of components for the passed format constant, e.g. 3 for
	///   VERTEXDESC_FORMAT_FLOAT3. Also descriptor members can be passed here.
	AE_DLLIMPEXP static AEINT32 GetComponentCountForFormat( AEINT32 nFormat );
	
	/// \brief Returns the size of the components for the passed format constant, e.g. 4 for
	///   VERTEXDESC_FORMAT_FLOAT3, and 2 for VERTEXDESC_FORMAT_SHORT4. Also descriptor members can be passed here.
	AE_DLLIMPEXP static AEINT32 GetComponentSizeForFormat( AEINT32 nFormat );

	/// \brief Static helper function to retrieve components from vertex 
	/// raw data in AEFLOAT32 format.
	/// This function performs format conversion so that the target format is always based on AEFLOAT32, regardless of the passed format.
	/// The interpretation of non-AEFLOAT32 formats is the same as inside vertex shaders, i.e. VERTEXDESC_FORMAT_SHORT2N converts from -32767..32767 to -1..1 range.
	/// \param pRawVertexData The source vertex data to read data from
	/// \param iOfsAndFormat
	///   The format specifier, that is compatible with the m_sPosOfs,... members of the descriptor class. The offset is used as an offset in the array
	///   and to format is used for format conversion.
	/// \param pDestFloat Target array that receives the converted components. 
	/// The array must be large enough for 1..4 floats, depending on the format
	/// \returns
	///   The number of components written (e.g. 3 for VERTEXDESC_FORMAT_FLOAT3). Or 0 if iOfsAndFormat==-1 
	AE_DLLIMPEXP static AEINT32 GetAsFloatArray( const void *lpRawVertexData, AEINT32 nOfsAndFormat, AEFLOAT32 *lpDestFloat );

	/// \brief
	///   The exact opposite of GetAsFloatArray: Writes AEFLOAT32 values into a buffer with specified format
	AE_DLLIMPEXP static AEINT32 SetAsFloatArray( void *lpRawVertexData, AEINT32 nOfsAndFormat, const AEFLOAT32 *lpSrcFloat );
	
	/// @}
	/** @name Check di uguaglianza */
	/// @{
	/// \brief
	///   Returns the hash code for this vertex descriptor. Internally used to optimize rendering.
	AE_FORCEINLINE AEUINT32 GetHash( void ) const;

	/// \brief Computes the internal hash value for this vertex descriptor. 
	AE_DLLIMPEXP void ComputeHash( void );

	/// \brief
	///   Compares two descriptors and returns true if they are absolutely identical. Requires that the hash is computed properly for both
	AE_DLLIMPEXP AEBOOL32 Equals( const AEVertexDescriptor &other ) const;

	/// \brief
	///   Compares two descriptors and returns true if they are absolutely identical. Requires that the hash is computed properly for both
	AE_FORCEINLINE AEBOOL32 operator == ( const AEVertexDescriptor& other ) const;

	/// \brief
	///   Compares two descriptors and returns true if they differ in any property
	AE_FORCEINLINE AEBOOL32 operator != ( const AEVertexDescriptor& other ) const;
	/// @}
};

#include "AEVertexDescriptor.inl"

#endif // _AEVERTEXDESCRIPTOR_H_
